﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace CILtoNative
{
    class Program
    {

        private static string EntryPointCode = string.Empty;
        private static PlugManager pManage;

        static void Main(string[] args)
        {
            NativeStrings.LoadStrings();
            ConsoleHelper.WriteLine(ConsoleColor.Cyan, "Loading Plugs...");
            pManage = new PlugManager();
            pManage.SetupAndLoad();
            ConsoleHelper.WriteLine(ConsoleColor.Cyan, "Plugs Loaded.");
            if (args != null && args.Length > 0)
            {
                Console.WriteLine("Input assembly: " + args[0]);
                //Load Assembly
                AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(args[0]);
                Console.WriteLine("Loaded AssemblyDefinition");
                //Loop through Modules
                foreach (ModuleDefinition mod in asm.Modules)
                {
                    foreach (TypeDefinition typedef in mod.Types)
                    {
                        AnalizeType(typedef, asm);
                    }
                }
            }
            else
            {
                ConsoleHelper.WarnLine("No input assembly.");
                Console.Write("Press any key to continue...");
                Console.ReadKey();
                return;
            }
            System.IO.File.WriteAllText("unplugged.txt", string.Join(Environment.NewLine, MethodEmitter.UnpluggedMethods));
            System.IO.File.WriteAllText("main.cpp", ProgramWrapper.WrapEntryPoint(EntryPointCode));
            ConsoleHelper.SuccessLine("Compiling...");
            string NewName = System.IO.Path.GetFileNameWithoutExtension(args[0]) + "_Native.exe";
            NativeCompile.CompileMainCpp(NewName);
            //Done...
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }

        private static void AnalizeType(TypeDefinition type, AssemblyDefinition asm)
        {
            foreach (TypeDefinition tdf in type.NestedTypes)
            {
                AnalizeType(tdf, asm);
            }
            foreach (MethodDefinition mdef in type.Methods)
            {
                if (!mdef.IsRuntime && !mdef.IsRuntimeSpecialName)
                {
                    if (mdef.HasBody)
                    {
                        for (int i = 0; i < mdef.Body.Instructions.Count; i++)
                        {
                            Instruction inst = mdef.Body.Instructions[i];
                            //Check if entry point (main.cpp)
                            if (mdef == asm.EntryPoint)
                            {
                                string NativeLine = MethodEmitter.GetNativeMethod(inst.ToString(), pManage);
                                if (!string.IsNullOrEmpty(NativeLine))
                                {
                                    EntryPointCode += NativeLine + Environment.NewLine;
                                }
                            }
                            Console.WriteLine(inst.ToString());
                        }
                    }
                }
            }
        }
    }
}
